/*
 * Copyright (C) 2014 Sony Computer Entertainment Inc.
 */

#include "config.h"
#include "CanvasBuffer.h"

#include <stdio.h>

#define GL_CMD(...) do { __VA_ARGS__; GLenum err = glGetError(); if (err) { fprintf(stderr, "L.%d: %08x\n", __LINE__, err); printf("\t%s\n", #__VA_ARGS__); } } while (0)
// #define GL_CMD(...) __VA_ARGS__;

namespace WebKit {

CanvasBuffer::CanvasBuffer()
    : m_width(0)
    , m_height(0)
    , m_fbo(0)
    , m_currentBufferIndex(0)
{
    for (int i = 0; i < NumBuffers; ++i) {
        m_buffers[i].tex = 0;
        m_buffers[i].reg = 0;
    }
}

CanvasBuffer::~CanvasBuffer()
{
}

void CanvasBuffer::initialize(int width, int height)
{
    terminate();

    m_width = width;
    m_height = height;

    for (int i = 0; i < NumBuffers; ++i) {
        GL_CMD(glGenTextures(1, &m_buffers[i].tex));
        GL_CMD(glBindTexture(GL_TEXTURE_2D, m_buffers[i].tex));
        GL_CMD(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR));
        GL_CMD(glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR));
        GL_CMD(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE));
        GL_CMD(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE));
        GL_CMD(glTexImage2D(GL_TEXTURE_2D, 0, GL_BGRA_EXT, width, height, 0, GL_BGRA_EXT, GL_UNSIGNED_BYTE, 0));

        GLsizei platformTextureSize = sce::CanvasUtil::platformTextureSize();
        m_buffers[i].reg = memalign(sce::CanvasUtil::platformTextureAlignment(), platformTextureSize);
        GL_CMD(glMapTextureResource(GL_TEXTURE_2D, m_buffers[i].reg, &platformTextureSize));
    }
    
    GL_CMD(glBindTexture(GL_TEXTURE_2D, 0));

    GL_CMD(glGenFramebuffers(1, &m_fbo));
}

void CanvasBuffer::terminate()
{
    if (m_fbo) {
        GL_CMD(glBindFramebuffer(GL_FRAMEBUFFER, 0));
        GL_CMD(glDeleteFramebuffers(1, &m_fbo));
        m_fbo = 0;
    }
    for (int i = 0; i < NumBuffers; ++i) {
        GL_CMD(glBindTexture(GL_TEXTURE_2D, m_buffers[i].tex));
        GL_CMD(glUnmapTextureResource(GL_TEXTURE_2D));
        GL_CMD(glBindTexture(GL_TEXTURE_2D, 0));
        GL_CMD(glDeleteTextures(1, &m_buffers[i].tex));
        m_buffers[i].tex = 0;

        free(m_buffers[i].reg);
        m_buffers[i].reg = 0;
    }
}

void CanvasBuffer::activateAsFrameBuffer()
{
    GLuint tex = m_buffers[m_currentBufferIndex].tex;
    GL_CMD(glBindFramebuffer(GL_FRAMEBUFFER, m_fbo));
    GL_CMD(glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex, 0));
    GL_CMD(glViewport(0, 0, m_width, m_height));
}

void CanvasBuffer::activateAsCanvas(sce::Canvas::Id id)
{
    sce::CanvasUtil::bindTexture(id, m_buffers[m_currentBufferIndex].reg);
}

void CanvasBuffer::rotateBuffers()
{
    m_currentBufferIndex = (m_currentBufferIndex + 1) % NumBuffers;
    // m_currentBufferIndex = 0; // Use single buffer mode.
}

}
